package org.candan.spider.task.xml;

import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Timer;

import org.apache.log4j.Logger;
import org.candan.spider.bean.Plan;
import org.candan.spider.bean.Result;
import org.candan.spider.bean.Task;
import org.candan.spider.task.Container;
import org.candan.spider.task.IPlanService;
import org.candan.spider.task.spider.SpiderFactory;
import org.candan.spider.util.DateUtil;
import org.candan.spider.util.SLog;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;


public class PlanXMLParse extends XMLParseAbstract implements IPlanService {
	
	private ResultXMLParse rp = new ResultXMLParse();
	private Logger logger = new SLog("计划执行类").getLogger();
	
	@Override
	public void runPlans(Map<String,Plan> plans) {
		logger.info("定时执行今日所有计划");
		Plan p;
		int i = 0;
		String[] keys = plans.keySet().toArray(new String[0]);
		for(String key : keys){
			p = plans.get(key);
			if(p.getStartTime().getTime() - new Date().getTime() < -180000){
				p.setStatus(XMLProperty.STATUS_OLD);
				Container.updatePlan(p);
				continue;
			}
			if(p.getTimer() == null){
				p.setTimer(new Timer());
			}
			p.getTimer().scheduleAtFixedRate(SpiderFactory.getDownTask(p), p.getStartTime(), 100000);
		}
	}
	
	@Override
	public void initPlan(Date date) {
		logger.info(DateUtil.getDayDateStr(date)+"计划加载到容器");
		List list = readXML(getPlanXMLFile(DateUtil.getDayDateStr(date))).getRootElement().selectNodes(XMLProperty.plan);
		Iterator iter = list.iterator();
		Plan pl = null;
		while (iter.hasNext()) {
			pl =xmlToPlan( (Element) iter.next());
			if(pl.getStatus().equalsIgnoreCase(XMLProperty.STATUS_WAIT)){
				Container.putPlan(pl);
			}
		}
		
	}

	@Override
	public boolean createDayPlans(Map<String,Task> tasks, Date fromTime,boolean isCover) {
		if(isCover || !isCover && !DateUtil.fileExist(getPlanXMLFile(fromTime))){
			logger.info(DateUtil.getDayDateStr(fromTime)+" 计划创建："+getPlanXMLFile(fromTime));
			createDayPlans(tasks, getPlanXMLFile(fromTime), fromTime);
		}else{
			logger.info(DateUtil.getDayDateStr(fromTime)+" 计划已存在："+getPlanXMLFile(fromTime));
		}
		return true;
	}
	/**
	 * @category 创建任务计划-每天自创建
	 * @param tks
	 * @param path
	 * @param strDate 每日的初始时间
	 * @return
	 */
	public boolean createDayPlans(Map<String,Task> tks, String path,Date strDate){
		
		 Document document = DocumentHelper.createDocument();
	     Element root = document.addElement(XMLProperty.plans);
	     for(Task tk : tks.values()){
	    	 insertPlan(root, tk, strDate);
	    	 
	     }
	     logger.info("计划创建完成");
	     serialize(document, path);
	     logger.info("计划创建序列化到"+path);
		return true;
	}
	
	
	
	/**
	 * @category 创建运行计划-临时创建任务时
	 * @param path
	 * @param task
	 * @param strDate 每日的初始时间
	 */
	public void createPlan(String path,Task task, Date strDate){
		Document document = readXML(path);
		insertPlan(document.getRootElement(), task, strDate);
		serialize(document, path);
	}
	
	/**
	 * @category 创建任务的运行计划
	 * @param root
	 * @param task
	 * @param strDate 每日的初始时间
	 */
	private void insertPlan(Element root, Task task, Date strDate){
		logger.info("创建任务'"+task.getName()+"' 的"+DateUtil.getDayDateStr(strDate)+"计划");
		Element child = null;
		long toTime = DateUtil.getDayDate(DateUtil.getDayDateStr(strDate)).getTime() + DateUtil.oneDayMsec;
		long fromTime;
		Date toDate = new Date();
		toDate.setTime(toTime);
		if(task.getStartTime().after(toDate)){
			return ;
		}
		fromTime = task.getStartTime().getTime() + 
		((strDate.getTime() - task.getStartTime().getTime())/task.getInterval()+1)
		* task.getInterval();
		
		for(; fromTime <= toTime; fromTime += task.getInterval()){
			child = new DefaultElement(XMLProperty.plan);
			child.addAttribute(XMLProperty.id, createID());
			child.addAttribute(XMLProperty.name, task.getName());
			child.addAttribute(XMLProperty.parent, task.getId());
			
			child.addAttribute(XMLProperty.status, XMLProperty.STATUS_WAIT);
			child.addAttribute(XMLProperty.startTime, DateUtil.dateFormat.format(new Date(fromTime)));
			child.addAttribute(XMLProperty.endTime, "");
			child.addAttribute(XMLProperty.url, task.getUrl());
			child.addAttribute(XMLProperty.output, task.getOutput());
			child.add(new DefaultElement(XMLProperty.results));
			root.add(child);
		}
	}
	
	private String createID(){
		return new Date().getTime()+""+((long)(Math.random()*9000+1000));
	}
	
	
	/**
	 * @category Plan转换成XML
	 * @param plan
	 * @return
	 */
	public Element planToXML(Plan plan){
		Element el = new DefaultElement(XMLProperty.plan);
		
		el.addAttribute(XMLProperty.id, plan.getId());
		el.addAttribute(XMLProperty.name, plan.getName());
		el.addAttribute(XMLProperty.parent, plan.getParent());
		el.addAttribute(XMLProperty.status, plan.getStatus());
		el.addAttribute(XMLProperty.startTime, DateUtil.getDateStr(plan.getStartTime()));
		el.addAttribute(XMLProperty.endTime, DateUtil.getDateStr(plan.getEndTime()));
		el.addAttribute(XMLProperty.url, plan.getUrl());
		el.addAttribute(XMLProperty.output, plan.getOutput());
		
		Element results = new DefaultElement(XMLProperty.results);
		if(plan.getResult().size()>0){
			for(Result rts: plan.getResult()){
				results.add(rp.resultToXML(rts));
			}
		}
		el.add(results);
		return el;
	}
	
	/**
	 * @category xml转换成Plan实体类
	 * @param el
	 * @return
	 */
	public Plan  xmlToPlan(Element el){
		Plan plan = new Plan();
		plan.setId(el.attributeValue(XMLProperty.id));
		plan.setName(el.attributeValue(XMLProperty.name));
		plan.setParent(el.attributeValue(XMLProperty.parent));
		plan.setStatus(el.attributeValue(XMLProperty.status));  
		plan.setStartTime(DateUtil.getDate(el.attributeValue(XMLProperty.startTime))) ;
		plan.setEndTime(DateUtil.getDate(el.attributeValue(XMLProperty.endTime))) ;
		plan.setUrl(el.attributeValue(XMLProperty.url));  
		plan.setOutput(el.attributeValue(XMLProperty.output));  
		
		List list = el.selectNodes(XMLProperty.results+"/"+XMLProperty.result);
		Iterator iter = list.iterator();
		Element etl = null;
		while (iter.hasNext()) {
			etl = (Element) iter.next();
			plan.getResult().add(rp.xmlToResult(etl));
		}
		return plan;
	}
	
	/**
	 * @category xml同步控制锁
	 * @param index 1:创建，2：更改  3：删除
	 * @param task
	 */
	synchronized public boolean changeXML(String file, int index, Element el){
//		 (file) {
			Document document = readXML(file);
			switch(index){
			case 1:
				insertPlan(document.getRootElement(),el);
				break;
			case 2:
				updatePlan(document.getRootElement(),el);
				break;
			case 3:
				removePlan(document.getRootElement(),el);
				break;
			default: return false;
			}
			serialize(document,file);
			
//		}
		return true;
	}
	
	
	/**
	 * @category xml增加任务
	 * @param el
	 * @return
	 */
	public Boolean insertPlan(Element root, Element el){
		root.add(el);
		return true;
	}
	
	/**
	 * @category xml删除计划
	 * @param root
	 * @param el
	 */
	public void removePlan(Element root,Element el){
		root.remove(el);
	}
	/**
	 * @category xml更改计划
	 * @param el
	 * @return
	 */
	public Boolean updatePlan(Element root, Element el){
		root.remove(searchElementByElementID(root,el));
		insertPlan(root,el);
		return true;
	}
	/**
	 * @category xml查询计划
	 * @param id
	 * @return
	 */
	public Element searchElementByID(Element root, String id){
		return (Element) root.selectSingleNode(XMLProperty.plan+"[@id='"+id+"']");
		
	}
	
	/** @category xml查询计划
	 * @param el
	 * @return
	 */
	public Element searchElementByElementID(Element root, Element el){
		return searchElementByID(root,el.attributeValue(XMLProperty.id));
		
	}

	@Override
	public boolean modifyPlan(Plan plan) {
		// TODO Auto-generated method stub
		String file = getPlanXMLFile(plan.getStartTime());
		if(!DateUtil.fileExist(file)){
			return false;
		}
		changeXML(file, 2, planToXML(plan));
		return true;
		
	}

	@Override
	public void createPlan(Plan plan) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void deletePlanByID(String id) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Plan searchPlanByID(String id) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<Plan> searchAllPlan(String date) {
		List<Plan> plansLs = new LinkedList<Plan>();
		List list = readXML(getPlanXMLFile(date)).getRootElement().selectNodes(XMLProperty.plan);
		Iterator iter = list.iterator();
		Element el = null;
		while (iter.hasNext()) {
			el = (Element) iter.next();
			plansLs.add(xmlToPlan(el));
		}

		return plansLs;
	}

	@Override
	public String searchAllPlanXml(String date) {
		return readXML(getPlanXMLFile(date)).getRootElement().asXML();
	}

	@Override
	public boolean deletePlan(Plan plan) {
		// TODO Auto-generated method stub
		String file = getPlanXMLFile(plan.getStartTime());
		if(!DateUtil.fileExist(file)){
			return false;
		}
		changeXML(file, 3, planToXML(plan));
		return true;
	}

	
	
}
